/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#
# exp = the expected new value of dst after merging
# nil = the expected new value of src after merging with rvalue-ref
#

cpp_include "thrift/test/fatal_merge_types.h"

namespace cpp2 apache.thrift.test

enum FooBar {
  kFoo = 0,
  kBar = 1,
}

struct EnumExample {
  1: FooBar src,
  2: FooBar dst,
  3: FooBar exp,
  4: FooBar nil,
}

const EnumExample kEnumExample = {
  "src": FooBar.kBar,
  "dst": FooBar.kFoo,
  "exp": FooBar.kBar,
  "nil": FooBar.kBar,
}

struct Basic {
  1: string b,
  2: optional string b_opt,
  3: required string b_req,
}

struct BasicExample {
  1: Basic src,
  2: Basic dst,
  3: Basic exp,
  4: Basic nil,
}

const BasicExample kBasicExample = {
  "src": {
    "b": "hello",
    "b_opt": "hello_opt",
    "b_req": "hello_req",
  },
  "dst": {
  },
  "exp": {
    "b": "hello",
    "b_opt": "hello_opt",
    "b_req": "hello_req",
  },
  "nil": {
    "b_opt": "",
  },
}

const BasicExample kBasicOptionalExample = {
  "src": {
    "b": "hello",
    "b_req": "hello_req",
  },
  "dst": {
    "b_opt": "hello_opt",
  },
  "exp": {
    "b": "hello",
    "b_opt": "hello_opt",
    "b_req": "hello_req",
  },
  "nil": {
  },
}

struct BasicList {
  1: list<Basic> l,
}

struct BasicListExample {
  1: BasicList src,
  2: BasicList dst,
  3: BasicList exp,
  4: BasicList nil,
}

const BasicListExample kBasicListExample = {
  "src": {
    "l": [
      {
        "b": "hello",
      },
    ],
  },
  "dst": {"l": []},
  "exp": {
    "l": [
      {
        "b": "hello",
      },
    ],
  }
  "nil": {
    "l": [
      {
      },
    ],
  },
}

struct BasicSet {
  1: set<Basic> l,
}

struct BasicSetExample {
  1: BasicSet src,
  2: BasicSet dst,
  3: BasicSet exp,
  4: BasicSet nil,
}

const BasicSetExample kBasicSetExample = {
  "src": {
    "l": [
      {
        "b": "hello",
      },
    ],
  },
  "dst": {"l": []},
  "exp": {
    "l": [
      {
        "b": "hello",
      },
    ],
  }
  "nil": {
    "l": [
      {
        "b": "hello", # cannot actually move elements
      },
    ],
  },
}

struct BasicMap {
  1: map<string, Basic> l,
}

struct BasicMapExample {
  1: BasicMap src,
  2: BasicMap dst,
  3: BasicMap exp,
  4: BasicMap nil,
}

const BasicMapExample kBasicMapExample = {
  "src": {
    "l": {
      "foo": {
        "b": "hello",
      },
    },
  },
  "dst": {"l": {}},
  "exp": {
    "l": {
      "foo": {
        "b": "hello",
      },
    },
  },
  "nil": {
    "l": {
      "foo": {
      },
    },
  },
}

struct NestedMap {
  1: map<string, map<string, Basic>> l,
}

struct NestedMapExample {
  1: NestedMap src,
  2: NestedMap dst,
  3: NestedMap exp,
  4: NestedMap nil,
}

const NestedMapExample kNestedMapExample = {
  "src": {
    "l": {
      "outer_foo": {
        "inner_foo": {
          "b": "hello",
        },
      },
    },
  },
  "dst": {
  },
  "exp": {
    "l": {
      "outer_foo": {
        "inner_foo": {
          "b": "hello",
        },
      },
    },
  },
  "nil": {
    "l": {
      "outer_foo": {
        "inner_foo": {
        },
      },
    },
  },
}

struct Nested {
  1: Basic a,
  2: Basic b,
  3: string c,
  4: string d,
}

struct NestedExample {
  1: Nested src,
  2: Nested dst,
  3: Nested exp,
  4: Nested nil,
}

const NestedExample kNestedExample = {
  "src": {
    "b": {
      "b": "hello",
    },
    "d": "bar",
  },
  "dst": {
    "a": {
      "b": "world",
    },
    "c": "foo",
  },
  "exp": {
    "a": {
      "b": "", # shouldn't this be "world"?
    },
    "b": {
      "b": "hello",
    },
    "c": "", # shouldn't this be "foo"?
    "d": "bar",
  },
  "nil": {
  },
}

struct NestedRefUnique {
  1: optional Basic a (cpp.ref_type = "unique"),
  2: optional Basic b (cpp.ref_type = "unique"),
  3: string c,
  4: string d,
}

struct NestedRefUniqueExample {
  1: NestedRefUnique src,
  2: NestedRefUnique dst,
  3: NestedRefUnique exp,
  4: NestedRefUnique nil,
}

const NestedRefUniqueExample kNestedRefUniqueExample = {
  "src": {
    "b": {
      "b": "hello",
    },
    "d": "bar",
  },
  "dst": {
    "a": {
      "b": "world",
    },
    "c": "foo",
  },
  "exp": {
    # "a": {"b": ""}, # why not this?
    "b": {
      "b": "hello",
    },
    "c": "", # shouldn't this be "foo"?
    "d": "bar",
  },
  "nil": {
  },
}

struct NestedRefShared {
  1: optional Basic a (cpp.ref_type = "shared"),
  2: optional Basic b (cpp.ref_type = "shared"),
  3: string c,
  4: string d,
}

struct NestedRefSharedExample {
  1: NestedRefShared src,
  2: NestedRefShared dst,
  3: NestedRefShared exp,
  4: NestedRefShared nil,
}

const NestedRefSharedExample kNestedRefSharedExample = {
  "src": {
    "b": {
      "b": "hello",
    },
    "d": "bar",
  },
  "dst": {
    "a": {
      "b": "world",
    },
    "c": "foo",
  },
  "exp": {
    # should "a" be {"b": ""}?
    "b": {
      "b": "hello",
    },
    "c": "", # shouldn't this be "foo"?
    "d": "bar",
  },
  "nil": {
  },
}

struct NestedRefSharedConst {
  1: optional Basic a (cpp.ref_type = "shared_const"),
  2: optional Basic b (cpp.ref_type = "shared_const"),
  3: string c,
  4: string d,
}

struct NestedRefSharedConstExample {
  1: NestedRefSharedConst src,
  2: NestedRefSharedConst dst,
  3: NestedRefSharedConst exp,
  4: NestedRefSharedConst nil,
}

const NestedRefSharedConstExample kNestedRefSharedConstExample = {
  "src": {
    "b": {
      "b": "hello",
    },
    "d": "bar",
  },
  "dst": {
    "a": {
      "b": "world",
    },
    "c": "foo",
  },
  "exp": {
    # should "a" be {"b": ""}?
    "b": {
      "b": "hello",
    },
    "c": "", # shouldn't this be "foo"?
    "d": "bar",
  },
  "nil": {
  },
}

typedef i32 (cpp.type = 'CppHasANumber', cpp.indirection = '.number') HasANumber

struct Indirection {
  1: i32 real,
  2: HasANumber fake,
}

struct IndirectionExample {
  1: Indirection src,
  2: Indirection dst,
  3: Indirection exp,
  4: Indirection nil,
}

const IndirectionExample kIndirectionExample = {
  "src": {
    "real": 45,
    "fake": 33,
  },
  "dst": {},
  "exp": {
    "real": 45,
    "fake": 33,
  },
  "nil": {
    "real": 45,
    "fake": 33,
  }
}

union BasicUnion {
  1: i32 a,
  2: string b,
}

struct BasicUnionExample {
  1: BasicUnion src,
  2: BasicUnion dst,
  3: BasicUnion exp,
  4: BasicUnion nil,
}

const BasicUnionExample kBasicUnionExample1 = {
  "src": {
    "a": 1,
  },
  "dst": {
  },
  "exp": {
    "a": 1,
  },
  "nil": {
  },
}

const BasicUnionExample kBasicUnionExample2 = {
  "src": {
  },
  "dst": {
    "a": 1,
  },
  "exp": {
  },
  "nil": {
  },
}

const BasicUnionExample kBasicUnionExample3 = {
  "src": {
    "a": 2,
  },
  "dst": {
    "a": 1,
  },
  "exp": {
    "a": 2,
  },
  "nil": {
  },
}

const BasicUnionExample kBasicUnionExample4 = {
  "src": {
    "a": 1,
  },
  "dst": {
    "b": "wat",
  },
  "exp": {
    "a": 1,
  },
  "nil": {
  },
}

struct MapUnion {
  1: map<i64, BasicUnion> l,
}

struct MapUnionExample {
  1: MapUnion src,
  2: MapUnion dst,
  3: MapUnion exp,
  4: MapUnion nil,
}

const MapUnionExample kMapUnionExample = {
  "src": {
    "l": {
      1: {"a": 1,},
    },
  },
  "dst": {
    "l": {
    },
  },
  "exp": {
    "l": {
      1: {"a": 1,},
    },
  },
  "nil": {
    "l": {
      1: {},
    },
  },
}
